블로그 프로젝트 - PoC 0 - 학습, 설계, 날먹, 언어 선택
저번 시간에는 내가 왜 굳이 블로그 서비스를 직접 만들었는지 설명했다. 사실 솔직히 그 당시에는 심심하기도 하고 웹 공부도 하고 네이버 블로그도 버릴 겸 만든 게 맞다. 몇몇 이유, 특히 취업 관련해서는 한참 지나고 생각해보니 그것도 맞는 듯해서 넣었다.
이번 시간에는 블로그 프로젝트의 첫번째 Proof of Concept: poc0를 어떻게 만들었는지, 만들면서 무엇을 배웠는지, 결국 왜 버리고 다음 PoC를 만들었는지 알아보자.
참고로 나는 이전까지는 온전한 웹 서비스를 만든 적이 한번도 없다. 그래서 처음에는 일단 웹과 인터넷에 대해서 공부하기 시작했다. 물론 이론 없이 바로 기술 정하고 코딩에 뛰어들수도 있다. 음.. 말하자면 김치국 웹기술 국룰 중에 국룰: js 리액트 프론트 + 갓바 스프링 백엔드 + RDB로 시작할 수도 있긴 했다.
그러나 석사할 때 도메인에 대해 제대로 모르고 설치다가 개같이 실패한 경험이 이번에는 나를 막았다.
인터넷과 웹 공부
매일 인터넷과 웹을 무슨 공기나 시냇물처럼 자연의 일부인 양 쓰고 있지만, 실제로 어떻게 작동하는지는 몰랐다.
그래서 먼저 컴퓨터 네트워크 탑다운 어프로치 책(NTD)을 봤다. 그런데 나는 웹 사이트를 만드니까, 굳이 TCP 단까지 내려갈 필요는 없었다. 그래서 그냥 2장 응용단까지만 읽었다. 2장에 나오는 웹 페이지 관련 내용이 큰 도움이 되었다.
브라우저의 개발자 콘솔에서 보면 페이지를 이루는 소스 파일들이 디렉토리 형식으로 정리된 걸 볼 수 있었는데, 항상 이게 어디에 저장이 되나? 궁금했었다. 책을 보면서 그런 건 브라우저의 구현 상세 사항(implementation detail)이고, 그냥 url의 구조에 따라 표시해 준다는 걸 알았다.
또한 NTD책 이외에도 ping, port, 소켓의 정체-사용-관리에 대해 알아보려고 CS:APP 책을 오랜만에 다시 보기도 하고, RFC나 리눅스 man페이지 등 만든 사람들이 직접 작성한 공식 문서를 보려고 노력했다. 이 또한 공식 문서가 아닌 어중이 떠중이가 쓴 블로그나 스오플 같은 것에 의존하다가 피를 본적이 많아서 그랬다.
핑, 포트, 소켓 같은 것들은 지금 생각해보면 딱히 웹사이트 개발에 직접적인 도움이 된 것은 아니지만, 그냥 궁금해서 조사를 하고 정리를 했다. (당장 만드는 게 바쁜 직업 프로젝트였으면 못했을지도 모른다)
- kur2204092034.Ping의 정체와 사용
- kur2204101401.port는 프로세스 하나가 독점하는, 컴퓨터 네트워크의 가상적 연결점이다
- kur2204182202.Socket소켓은 Application 계층과 Transport 계층 사이의 인터페이스다
이렇게 공부하고 나니 웹 서버가 대충 뭐하는 놈이며 어디에 어떻게 설치해야 하고, HTTPS는 무엇이며 왜 써야 하고, 도메인이 무엇이고 어떻게 하면 내 걸 가질 수 있는지 등등 웹의 기초를 배울 수 있었다.
슬슬 당장 서비스를 만들고 싶어 근질거리기 시작했다. 하지만 경거망동하지 마라. 차근차근 학습하면서 탄탄하게 개발하는 게 내 새로운 개발 철학이잖나. 이 때부터 어떤 블로그를 만들지 생각했고, 그 결과는 이전 글에서 상세하게 설명한 조건들(요구사항)이다.
PoC 0의 설계
보통 취준생들이 흔히들 블로그를 만든다면서 무슨 DB에 로그인에 에디터까지 만드는 경우가 있다. 그럼 식으로 했다가는 퀄리티 있는 블로그를 만드는 데는 1년도 부족할 수 있다. 물론 면접관들이야 좋아할 수도 있겠지만, 나는 애초에 포폴은 곁다리고 한번 만든 뒤 두고두고 울궈 먹을 서비스를 만들고자 했다. 그러자면 블로그 서비스를 사용하는 비용 뿐 아니라 만들고 관리하는 비용도 역시 낮아야 한다.
어떻게 하면 일을 덜 하고도 주기적으로 서비스에 새 피처가 추가되고 보안 문제가 고쳐지고 디자인이 아름다워지게 할 수 있을까?
답은 날로 먹기다.
기술 뽕맞은 친구들 중에 가끔 혀 꼬우면서 leverage라고도 하는데 날먹이 올바른 표현이다. 면접에서 꼭 쓰도록!
풺웤이나 라이브러리 정도가 아니라 아예 서비스를 갖다 써버리면 나는 아무 일도 안 해도 그 서비스 개발자들이 유저인 날 위해서 열심히 일해준다.
날로 먹는 기술
그래서 첫번째 PoC에서부터 날로 먹을 생각을 했다. 블로그 포스트 파일로는 md를 쓰고 에디터는 Obsidian을, 서버-데스크탑-모바일의 파일 동기화는 Syncthing을 썼다.
에디터나 데이터 동기화나 하나같이 까다로운 것들인데, 남들이 만든 제품을 갖다 써서 수많은 기능을 거의 공짜로 얻었다. 또한 개발 속도 뿐 아니라 성능, 안정성, 강건함 등 소프트웨어 품질까지 끌어올릴 수 있었다.
쟤네들 둘 다 대충 손 가는 대로 집은 게 아니라 심혈을 기울여 선택한 기술이다. 특히 모바일을 지원하는지가 정말 중요했다. 내게 블로그의 모바일 피처는 정말로 중요한데, 정작 나는 안드로이드 앱을 만들려고 갓바와 앙드 스튜디오로 똥꼬쇼 하는 게 너무 싫었다[1]. 그래서 최대한 날먹leverage하는 방향으로 가려고 했다. 결국 Syncthing과 Obsidian 모바일 앱을 적용, 단 한 줄의 코딩도 없이 모바일 피처를 낼름 날로 먹어버린다.
거르는 기술
DB는 안 썼다. 내 블로그에는 아무런 쓸모가 없다. 글은 나만 쓰고, 페이지는 그냥 정적 서빙하니까 파일만 있으면 충분하다. 이런 상황에서 DB는 그냥 거추장스러울 뿐이다.
비슷하게 리액트니 뷰js니 하는 프론트엔드 펢웤도 전혀 필요가 없다. 애초에 완전히 정적인 사이트라서 지금도 HTML과 CSS만 쓰고 있다. 나중에 JS가 필요하다고 해도 그냥 CLJS로 DOM을 직접 조지면 될거라고 생각한다.
명심하자. 기술을 쓰는 방법보다, 기술을 언제 쓰면 안 되는지 아는 것이 더 중요하다. 은총알은 없다는 말은 스프링, 리액트, RDB 같은 국밥도 결코 만병통치약이 아니라는 뜻이다. 잘 모루겠어서 일단 국밥을 시켰는데 개노맛일 때, 잘하는 집을 안가봐서 그래 라고 하지 말자. 그냥 그 사람(문제)한테는 국밥(솔루션)이 안 맞을 수도 있다는 거다.
아무튼 사용하는 기술들의 낄끼빠빠를 꼭 알아 두도록 하자.
정리
지금까지 한 설계를 정리해 보자.
날로 먹은 것
- 에디터: 데스크탑, 모바일에서 모두 Obsidian을 쓴다. 블로그 포스트의 파일 형식은 CommonMark 스펙의 마크다운에 Obsidian이 추가한 피처(위키링크
[[link#heading|text]]
, 임베딩 등)가 있는 형식이다. - 파일 동기화: Syncthing을 써서 폰, 데스크탑 어디에서 포스트를 작성해도 동기화 되고, 작성한 글이 바로 바로 서버로 전송된다.
이제 남은 것은 다음과 같다.
직접 만들 것
- 마크다운 파서: 물론 라이브러리를 쓰겠지만, 옵시디언 추가 피처를 전부 지원할 가능성은 낮다. 라이브러리를 확장해야할 것이다.
- 파일시스템 모니터: 씽크띵이 md파일을 서버에 동기화시키면, 그에 따라 적절한 주기로 마크다운 파서를 실행하여 html을 만든다.
- 웹 서버: 웹 api를 정의하고, 요청이 들어오면 요청에 맞게 마크다운 파서가 변환하여 만들어둔 html과 각종 리소스를 응답으로 보낸다.
서비스의 전체 데이터 흐름은 다음과 같다
<그림 추가할 것>
- 작가(나)가 데탑이나 폰에서 옵시디언으로 포스트를 작성한다
- 작성한 포스트는 마크다운으로 저장되고, 씽크띵이 데탑, 폰, 서버에 파일을 동기화시킨다
- 서버로 md 파일이 동기화되면 html 파일로 변환한다
- 독자의 브라우저에서 요청(req)이 들어오면 웹서버는 요청에 맞게 html을 독자에게 보낸다(resp)
댓글, 구독 시스템은 지금은 만들지 않기로 했다.
The Proof of Concepts
PoC가 왜 PoC인가? 뇌피셜이 작동하는지 알아 보기 때문에 PoC다. 킹론적으로는 가능한 거라고 해도, 무슨 돌발 사항으로 작동하지 않아 설계를 버려야 할 수도 있다. 이 바닥에서 한 번도 안 해 본 건 뭐가 됐든 간에, 진짜로 돌아가고 눈으로 볼 수 있기 전까지는 절대 믿지 말아야 한다.
The Concepts
내 설계의 핵심 가정은
- 1 옵시디언으로 데스크탑, 모바일에서 작성한 md를
- 2 씽크띵으로 데탑, 폰, 서버에 동기화하기이다.
1,2가 성공해야만
- 3 md를 마크다운 파서로 변환
- 4 서버에서 md가 동기화되면 파서를 실행하여 html 생성
- 5 변환한 html을 웹서버가 클라로 전송하는 게
의미가 있다
위 가정들은 전부 말도 되고 이론상으로는 충분히 가능해 보인다. 하지만 정말로 될까? 일단 서버를 사고 씽크띵부터 설치해 보았다.
Syncthing을 클라우드에서 써보기
서버는 AWS를 쓰기로 했다. 이 선택은 AWS가 그냥 개나 소나 처먹는 국밥 중에 국밥이라서 선택하긴 했다. 물론 EC2니 S3니 이걸 다루는 aws클리니 Terraform이니.. 배우면 좋기야 하겠지만 지금은 이런 쪽으로 공부하기보다는 당장 웹사이트를 띄우고 피드백을 받고 싶었다. 그래서 AWS 플랫폼을 쉽게 쓸 수 있는 VPS인 Lightsail을 썼다. 클라우드 플랫폼은 다룬 적이 없지만 ssh로 서버에 접속하여 작업한 적은 많았기 때문에, 큰 문제 없이 쓸 수 있었다.
AWS에 씽크띵을 설치하는데, 구글링해서 찾은 문서를 보고 따라 했다가 피를 봤다. 그리고 나서 공식 문서를 보고 제대로 설치하게 된다. 이 때 ZK에 일기처럼 남긴 글이 있다.
kur2204121903.anecdote."공식 문서를 읽으라"는 교훈을 얻은 Syncthing AWS Lightsail 설치 기록
교훈
- 공식 문서를 읽어라
- 로그(journalctl)를 보고 문제를 빠르게 파악하자
2022-04-09에 비공식 문서를 보고 AWS Lightsail에 Stncthing 설치를 완료함.
그러나 작동하지 않음. 8384 port로 접속하는 어드민 페이지에 접속이 불가능했음.
이유를 알 수 없어서 여러 모로 생각해보고 공부하다가 port에 대한 개념(kur2204101419.port를 열고 닫는 주체는 어플리케이션이다)과 방화벽 등을 알게 됨3일 후 2022-04-12에
journalctl -xefu
를 보고 기존 설치의 문제점을 깨닫음. 실행에 실패해서 계속해서 재시작하고 있었음(원인은 비공식 매뉴얼이 제공하는 .service 파일의 syncthing 실행 커맨드에서 브라우저가 있는 환경을 요구하는 것으로 추측됨)
결국 비공식 문서가 잘못되었다고 생각하여 공식문서를 보고 다시 설치하려 함.
공식 문서에는 다양한 예외사항과 rpm 패키지매니저 파일 링크도 있고 방화벽 이야기도 있고 훨씬 나았음. 공식문서를 보고 금방 설치에 성공하고 어드민 페이지에 접속함. 22000 포트의 방화벽을 뚫고 기기들의 sync에 성공함.
아무튼 우여곡절 끝에 씽크띵을 설치했고, 기기들 사이에서 완벽히 작동하는 것을 확인했다. 가정 1,2는 참이었다! 이제 3,4,5가 정말 되는지 알아보자 (안 될리가 없겠지만 아무튼 해보자)
언어, 플랫폼 선택: Clojure
그 전에 무슨 언어와 플랫폼으로 3 마크다운 파서, 4 파일시스템 모니터, 5 웹 서버를 만들지를 정해야 했다. 이제부터는 남이 만든 걸 갖다 쓰더라도 이리저리 변형하기 위해 프로그래밍이 필요한 시점이었다.
나는 4 fs모니터와 5 웹서버로 Clojure, JVM을 선택했다. 3 md파서는 ClojureScript와 node.js를 선택했다. (사실 clj와 cljs는 플랫폼만 다를 뿐 똑같은 언어다. 그냥 Clojure를 선택했다고 보면 된다)
왜 Clojure인가
[왜 Clojure인가?] 이에 대해서는 하루 죙일도 떠들 수가 있다. 다만 이 시점에서는 그냥 제일 잘 쓰는 언어여서 선택한 게 맞다. 그리고 JS처럼 프론트와 백엔드에서 코드를 공유할 수 있다는 점도 좋았다.
이제부터 말하는 것들은 선택 먼저 하고 그 이유를 만들어내는 자기 합리화일수도 있고, 직감적 선택을 한 나의 무의식을 파헤쳐 보는 것일 수도 있다.
Clojure외에 쓸 줄 아는 범용 언어는 대충 인싸 언어들 전부(Python, C/C++, Java, Javascript...)인데, 파이썬을 가장 잘 다루고 많이 써 봤었다. 내가 평범한 취준생이었다면 당연히 파이썬을 선택했을 것이다. 하지만 어림도 없지 나는 Clojure를 선택했다.
왜 인싸 언어를 안 썼나
내가 원한 언어는: 라이브러리 생태계가 풍부하고, Idiomatic한 코드가 함수형이고, 동적타입이며, 매우 stable하고, 프론트와 백에서 코드를 공유할 수 있는 무언가였다.
내가 쓸 줄 아는 언어 중 이걸 모두 만족하는 언어는 Clojure뿐이다.
- 인싸 언어들 중에서는 파이썬을 가장 잘 쓰고 오래 써왔지만 이번에는 매우 오래 가는 서비스를 만들어야 해서 걸렀다.
- 파이썬은 안정성stability이 심각하게 떨어지는 언어다. LTS라는 개념이 없고 모든 버전은 몇년 후 지원이 중단된다[2]. 심지어 과거 2.x 버전을 완전히 버리고 3.x로 갈아타는 만행을 저지른 적도 있다. 언어가 무슨 응용 프로그램인 줄 아나..
- 더욱 심각한 것은 라이브러리 개발자들도 이러한 문화에 경도된 건지 심심하면 피처를 deprecate시키고 지들 맘대로 API 이름 바꾸고 삭제하고 지랄 발광을 한다는 점이다.
- 그 결과는? 라이브러리 업뎃하면 터져나가는 코드와 전혀 건드리지 않았는데 1년만 지나도 작동하지 않는 코드이다. 이런 언어로는 나 혼자 한번 만들고 나서 몇 년이고 우려 먹을 서비스를 만들 수 없다.
- 평범한 웹 사이트를 C/C++로 만드는 사람은 약간 맛이 간 사람들 뿐이니 논외로 하자.
- 갓바와 JVM은 안정성이 매우 높은 언어와 플랫폼이다. 그런데 그건 Clojure도 그렇다. 함수형도 동적타입도 아니라서 걸렀다.
- 자바스크립트는 사실 매우 유망하다. 표현 뿐이긴 해도 함수형도 나름 쓸 수 있고 프론트 백 코드 공유도 된다. 인싸 언어를 쓰겠다면 JS를 선택하는 게 맞았겠지만, JS는 제일 덜 써 봐서 영 미숙하기도 했고, 이번 기회에 CLJS를 써 보고도 싶었다.
이렇게 많이 이야기를 했지만 솔직히 PoC 0를 만들 때 저걸 다 따지고 한 게 아니다. 진짜 취업해야 하니까 인싸 언어를 쓸까 아주 잠깐 고민한 적은 있지만 그냥 가슴이 시키는 걸 하기로 했다. 인생에서 만들고 싶은 걸 만들 수 있는 시간은 그리 길지 않으니까..
그래서 오래오래 행복하게 살았답니다!
언어로 근로저를 쓰기로 결정한 이 시점보다, 이후 시스템을 만들면서 Clojure의 압도적인 능력에 더욱 반하게 된다.
이 글에서는 자세히 설명하지 않겠지만, 리슾 매크로로 go의 고루틴을 구현해낸 core.async, cljc 파일을 통한 clj cljs 코드 공유, java와 js interop을 통한 방대한 라이브러리 생태계 날먹까지.. 근로저가 아니었다면 이 정도로 효과적인 개발은 불가능했을 것이다.
진짜 Clojure 이거 이렇게 좋은데 왜 안 쓸까? 입문해보고 싶다면 여기로.. ㅋ
이제 Clojure로 3 파서, 4 모니터, 5 서버를 어떻게 구현했는지 알아 보자
아니?! 벌써 8천자가 넘었잖아? 너무 길어졌다. 일단 여기서 한번 매듭짓고 가도록 하자
PoC 0 개발 1화 맺음말
과거의 실패 경험으로 인해 프밍에 바로 뛰어들기보다 웹, 인터넷 공부를 먼저 했다.
PoC 0를 설계했는데 핵심은 날먹leverage이다
- 에디터를 Obsidian으로 날로 먹는다
- 파일 동기화를 Syncthing으로 날로 먹는다
이제 짜야 하는 것은 3가지 뿐이다
- 마크다운 파서
- 파일 시스템 모니터
- 웹 서버
그런데 뭘로 짜느냐? Clojure로 짠다.
- 무슨 그런 듣보잡을 쓰냐고? 이러 저러 해서 쓴다.
- 마 Clojure 함 무바라 디진다 아이가!